﻿#include "bilaterafilter.h"


/*
* 获取滤波算子
* get table
* 注意，输入必须为单通道
*/
void Gattable(matrix intable, matrix outtable, matrix indata, int threshold) {
    int r, c, index;
    int cent;
    if (indata.channel > 1) {
        printf("ERROR<Gettable>:input one multi channel table!\n");
        exit(-1);
    }
    else {
        cent = indata.data[(indata.h >> 1) * indata.w + (indata.w >> 1)];
    }

    for (r = 0; r < intable.h; r++)
        for (c = 0; c < intable.w; c++) {
            index = r * indata.w + c;
            if (abs((int)indata.data[index] - cent) > threshold) {
                ((int*)outtable.d)[index] = 0;
            }
            else
                ((int*)outtable.d)[index] = ((int*)intable.d)[index];
        }
}

/*
* 对指定的矩阵进行双边滤波运算
*
*/
char Bilatera(matrix inmat, matrix outmat, matrix table) {
    int r, c, i, j, chan, index;
    int sum, t;
    matrix dbuf, ttable;
    ttable.d = (int*)malloc(table.h * table.w);
    dbuf.data = (uchar*)malloc(table.h * table.w);
    ttable.w = dbuf.w = table.w;
    ttable.h = dbuf.h = table.h;
    ttable.channel = dbuf.channel = 1;

    for (r = 0; r < inmat.h; r++) {
        for (c = 0; c < inmat.w; c++) {
            for (chan = 0; chan < inmat.channel; chan++) {
                //printf("indata:\n");
                for (i = 0; i < table.h; i++) {
                    for (j = 0; j < table.w; j++) {
                        if ((r + i - (table.h >> 1)) < 0 || c + j - (table.w >> 1) < 0 || (r + i - (table.h >> 1)) >= inmat.h || c + j - (table.w >> 1) >= inmat.w)
                            t = 0;      //padding value
                        else
                            t = inmat.data[((r + i - (table.h >> 1)) * inmat.w + c + j - (table.w >> 1)) * inmat.channel + chan];
                        dbuf.data[i * table.w + j] = t;
                        //printf("%d\t", dbuf.data[i * table.w + j]);
                    }
                    //std::cout << std::endl;
                }
                Gattable(table, ttable, dbuf, 40);      //get one table
                sum = 0;
                t = 0;
                //printf("\nrow:%d\tcol:%d\n", r, c);
                for (i = 0; i < table.h; i++) {
                    for (j = 0; j < table.w; j++) {
                        index = i * ttable.w + j;
                        //printf("%d\t", ((int*)ttable.d)[index]);
                        sum += ((int*)ttable.d)[index];
                        t += ((int*)ttable.d)[index] * dbuf.data[index];
                    }
                    //printf("\n");
                }
                //printf("sum:%d,t:%d", sum, t);
                t /= sum;
                outmat.data[(r * outmat.w + c) * outmat.channel + chan] = (uchar)(t > 255 ? 255 : t);
            }
        }
    }
    /*free((int *)ttable.d);
    free(dbuf.data); */   
    return OK;
}


char BilateraMask(matrix dstmat, matrix srcmat,matrix gtable, matrix mask) {
    if (srcmat.w <= 0 || srcmat.data == NULL || dstmat.w <= 0 || dstmat.data == NULL || gtable.w <= 0 || gtable.d == NULL || mask.w <= 0 || mask.data == NULL) {
        printf("ERROR! input is empty!\n");
        return FALSE;
    }
    if (srcmat.w != dstmat.w || dstmat.w != mask.w || dstmat.h != mask.h) {
        printf("ERROR! The mask and input sizes entered do not match!\n");
        return FALSE;
    }

    int r, c, i, j, chan,x,y,e;
    int sumv,sumt, t,*ghp,*gtp= (int *)gtable.d,v;        //gauss tabl point
    ghp = gtp;
    writeMat(srcmat, "testinput.ppm", PPM_P6_OUT);
    for (r = 0; r < srcmat.h; r++) {
        for (c = 0; c < srcmat.w; c++) {
            for (chan = 0; chan < srcmat.channel; chan++) {
                //printf("indata(%d,%d):\n",r,c);
                gtp = ghp;
                sumv = sumt = 0;
                e = mask.data[r * srcmat.w + c];
                if (c == 1932 && r == 33)
                    sumv = 0;
                /*if(!e)
                    continue;*/
                for (i = 0; i < gtable.h; i++) {
                    for (j = 0; j < gtable.w; j++) {
                        x = c + j - (gtable.w >> 1);
                        y = r + i - (gtable.h >> 1);
                        if (y < 0 || x < 0 || y >= srcmat.h || x >= srcmat.w) {
                            t = 0;
                            v = 0;
                        }
                        else {
                            if (mask.data[y * srcmat.w + x] != e)
                                t = *gtp*0.2;
                            else
                                t = *gtp;
                            v = srcmat.data[(y * srcmat.w + x) * srcmat.channel + chan];
                        }
                        sumv += v * t;
                        sumt += t;
                        gtp++;
                        //printf("%dx%d=%d\t", t, v, t * v);
                    }
                    //std::cout << std::endl;
                }
                //printf("\n\n\n");
                t = sumt ? sumv / sumt : 0;
                //t= srcmat.data[(r * srcmat.w + c) * srcmat.channel + chan];
                dstmat.data[(r * dstmat.w + c) * dstmat.channel + chan] = (uchar)(t > 255 ? 255 : t);
            }
        }
    }
    return OK;
}



char BilateraMasklvs(matrix dstmat, matrix srcmat, matrix gtable, matrix mask,matrix masktextbg,double *wts,int l) {
    if (srcmat.w <= 0 || srcmat.data == NULL || dstmat.w <= 0 || dstmat.data == NULL || gtable.w <= 0 || gtable.d == NULL || mask.w <= 0 || mask.data == NULL) {
        printf("ERROR! input is empty!\n");
        return FALSE;
    }
    if (srcmat.w != dstmat.w || dstmat.w != mask.w || dstmat.h != mask.h) {
        printf("ERROR! The mask and input's sizes entered do not match!\n");
        return FALSE;
    }
    int r, c, i, j, chan, x, y, e,lvi, lvl = clip(int(255 / l),0,255);
    int sharpwts[3][3] = { {0,-1,0},
                            {-1,5,-1 },
                            {0,-1,0}    },sharpsize=3;
    int sumv, sumt, t, * ghp, * gtp = (int*)gtable.d, v;        //gauss tabl point
    ghp = gtp;      //head point of gauss table ....temp point of gauss table 
    uchar * pmtb, * pmsk;
    pmtb = masktextbg.data;
    pmsk = mask.data;
    writeMat(mask, "testinput.ppm", PPM_P6_OUT);
    for (r = 0; r < srcmat.h; r++) {
        for (c = 0; c < srcmat.w; c++) {
            if (*pmtb > 0) {        //sharp                
                for (chan = 0; chan < srcmat.channel; chan++) {
                    t = 0;
                    for (i = 0; i < sharpsize; i++) {
                        for (j = 0; j < sharpsize; j++) {
                            x = c + j - (sharpsize >> 1);
                            y = r + i - (sharpsize >> 1);
                            if (y < 0 || x < 0 || y >= srcmat.h || x >= srcmat.w) {
                                continue;
                            }
                            t += sharpwts[i][j] * srcmat.data[(y * srcmat.w + x) * srcmat.channel + chan];
                        }
                    }
                    dstmat.data[(r * dstmat.w + c) * dstmat.channel + chan] = (uchar)(t > 255 ? 255 : t);
                }
            }
            else {
                for (chan = 0; chan < srcmat.channel; chan++) {
                    //printf("indata(%d,%d):\n",r,c);
                    gtp = ghp;
                    sumv = sumt = 0;
                    e = mask.data[r * srcmat.w + c];
                    //if (c == 1932 && r == 33)
                    //    sumv = 0;
                    /*if(!e)
                        continue;*/
                    for (i = 0; i < gtable.h; i++) {
                        for (j = 0; j < gtable.w; j++) {
                            x = c + j - (gtable.w >> 1);
                            y = r + i - (gtable.h >> 1);
                            if (y < 0 || x < 0 || y >= srcmat.h || x >= srcmat.w) {
                                t = 0;
                                v = 0;
                            }
                            else {
                                v = srcmat.data[(y * srcmat.w + x) * srcmat.channel + chan];
                                lvi = abs(mask.data[y * srcmat.w + x] - e) / lvl;
                                t = int(*gtp * wts[lvi]);
                            }
                            sumv += int(v * t);
                            sumt += t;
                            gtp++;
                            //printf("%dx%d=%d\t", t, v, t * v);
                        }
                        //std::cout << std::endl;
                    }

                    //printf("\n\n\n");
                    t = sumv / sumt;
                    //t= srcmat.data[(r * srcmat.w + c) * srcmat.channel + chan];
                    dstmat.data[(r * dstmat.w + c) * dstmat.channel + chan] = (uchar)(t > 255 ? 255 : t);
                }
            }
        }
    }
    return OK;
}